
import traceback
import time
from datetime import datetime

import coreapi
import coreschema
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.schemas import ManualSchema

import basic
from basic.models import ProcessNumber
from utils.binance import Binance
from binance_dgs.settings import Parameter as dgs_parameter
from utils.timestamp import time_stamp_date, now_time_stamp


# Create your views here.

# 清除所有缓存
# binance.cache_clear()   # 全局调试时开启，否则会丢logging配置


class HomeData(APIView):
    """
    数据首页接口
    """

    def get(self, request):

        try:
            binance = Binance(parameter=dgs_parameter, strategy=basic.Strategy.dgs)
        except:
            return JsonResponse({'code': 31400, 'msg': '操作请求体错误.'})

        # binance.logger_error(f"邮件测试!!!")

        process_obj = ProcessNumber.objects.filter(exchange=binance.exchange_name,
                                                   strategy=binance.strategy_name).first()
        cache = binance.cache_get(binance.parameter.db_coll_balance)
        # 计算运行天数

        start_time = int(cache[binance.parameter.db_coll_balance_timeStamp] / 1000)
        end_time = int(now_time_stamp() / 1000)
        run_days = (datetime.fromtimestamp(end_time) - datetime.fromtimestamp(start_time)).days

        tradings = binance.cache_get(binance.parameter.db_coll_trading_symbol) or []
        data = {
            "head": [
                {"type": "交易所可用余额", "text": f"{binance.exchange_available_balance()}U"},
                {"type": "启动模式", "text": "实盘" if process_obj.pan_opening == '0' else "模拟盘"},
                {"type": "平仓停止", "text": "启用中" if process_obj.status == '0' else "未启用"},
                {"type": "本地钱包余额", "text": f"{round(cache[binance.parameter.db_coll_balance], 2)}U"},
                {"type": "本地初始金额", "text": f"{round(cache[binance.parameter.db_coll_balance_init], 2)}U"},
                {"type": "运行", "text": f"{run_days}天"},
            ],  # 上部数据
            "symbols": [trading['symbol'][:-len(binance.parameter.ccy)] for trading in tradings]
        }
        return JsonResponse({'data': data, 'code': 200, 'msg': 'ok'})


class HomeDataSymbolDetails(APIView):
    """
    数据首页接口: 交易对详细数据
    """

    # docs文档参数
    schema = ManualSchema(
        description='数据首页接口: 交易对详细数据',
        fields=[
            coreapi.Field(name="symbol", required=True, location="form",
                          schema=coreschema.String(description="交易对名称（无需带上计价货币）")),
        ]
    )

    def post(self, request):

        try:
            binance = Binance(parameter=dgs_parameter, strategy=basic.Strategy.dgs)
        except:
            return JsonResponse({'code': 31400, 'msg': '操作请求体错误.'})

        symbol = f"{request.data['symbol']}{binance.parameter.ccy}"

        tradings = binance.cache_get(binance.parameter.db_coll_trading_symbol)
        # 生成器表达式遍历
        trading = next((item for item in tradings if item['symbol'] == symbol), None)

        # 获取最新价格
        def get_new_price(symbol_price):
            ticker_list = binance.cache_get(binance.parameter.db_coll_symbol_new_ticker_price)
            if ticker_list:
                for item in ticker_list:
                    if item["symbol"] == symbol_price:
                        return float(item["price"])
            return None

        data = binance.cache_get(f"{binance.exchange_strategy}_{symbol}")
        if trading and data:
            data["dgs"] = [
                {"type": "币种", "text": data["info"]["inst_id"][:-len(binance.parameter.ccy)]},
                {"type": "现价", "text": get_new_price(data["info"]["inst_id"])},
                {"type": "杠杆", "text": data["info"]["leverage"]},
                {"type": "模式", "text": "逐仓" if data["info"]["isolated"] == binance.parameter.isolated else "全仓"},
                {"type": "DGS数", "text": data["info"]["grid_number"]},
                {"type": "剩余U", "text": round(trading["real_u"], 2)},
                {"type": "实际U", "text": round(data["info"]["real_u"], 2)},
                {"type": "所需U", "text": round(data["info"]["all_u"], 2)},
                {"type": "状态", "text": "只平不开" if data["info"]["next"] or binance.cache_get(binance.parameter.db_coll_program) else "开仓平仓"},
                {"type": "启动时间",
                 "text": time.strftime("%m-%d %H:%M", time.localtime(data["info"]["start_number"] / 1000))},
                {"type": "停止时间", "text": time.strftime("%m-%d %H:%M", time.localtime(
                    data["info"]["next_time_stamp"] / 1000))},
            ]  # 交易对数据列表
            return JsonResponse({'data': data, 'code': 200, 'msg': 'ok.'})
        return JsonResponse({'data': data, 'code': 31505, 'msg': '系统数据错误.'})


class MineArgument(APIView):
    """
    我的页面：程序参数
    """

    def get(self, request):

        try:
            binance = Binance(parameter=dgs_parameter, strategy=basic.Strategy.dgs)
        except:
            return JsonResponse({'code': 31400, 'msg': '操作请求体错误.'})

        data = dict()
        profit_rapid = self.get_profit(binance)
        data["profit"] = profit_rapid["profit"]  # 利润间距
        data["rapid"] = profit_rapid["rapid"]  # 急速止盈/止损
        data["fgi"] = self.get_fear_and_greed_index(binance)  # 恐慌与贪婪指数
        data["balance"] = binance.exchange_available_balance()  # 交易所可用余额
        data["init_balance"] = self.get_init_balance(binance)  # 初始金额
        data["ccy"] = binance.parameter.ccy  # 计价货币
        data["commission"] = f"{binance.parameter.commission * 100}%"  # 手续费
        data["isolated"] = "逐仓" if binance.parameter.isolated == "ISOLATED" else "全仓"  # 持仓模式
        data["min_margin"] = f"{binance.parameter.set_margin}%"  # 最低保证金
        data["threshold"] = "未开发"  # 账户阀值(低于时退出程序)
        data["min_dgs_number"] = binance.parameter.set_min_dgs_number  # 最小DGS数量
        data["filtration_min_dgs_number"] = self.get_min_dgs_number(binance)  # 已过滤(最小DGS数)

        return JsonResponse({'data': data, 'code': 200, 'msg': 'ok'})

    @staticmethod
    def get_profit(binance):
        """ 利润间距和急速止盈/止损 """
        profit = []
        rapid = []
        tradings = binance.cache_get(binance.parameter.db_coll_trading_symbol) or []
        if tradings:
            for trading in tradings:
                dgs_data = binance.cache_get(f"{binance.exchange_strategy}_{trading['symbol']}")
                if dgs_data:
                    profit.append(dgs_data["info"]["profit_spacing"])
                    rapid.append(dgs_data["db"]["speed_tracking"][0]["fgi"])
                    rapid.append(dgs_data["db"]["speed_tracking"][1]["fgi"])
            profit.sort()
            rapid.sort()
            if not profit or not rapid:
                return {"profit": None, "rapid": None}

            return {
                "profit": f"{round(profit[0] * 100, 2)}% ~ {round(profit[-1] * 100, 2)}%",
                "rapid": f"{round(rapid[0] * 100, 2)}% ~ {round(rapid[-1] * 100, 2)}%"
            }

        return {"profit": None, "rapid": None}

    @staticmethod
    def get_fear_and_greed_index(binance):
        """ 恐慌与贪婪指数 """
        data = binance.cache_get(binance.parameter.db_coll_fgi)
        if data:
            return f"【{data['timestamp']}】{data['value']}"

        return None

    @staticmethod
    def get_init_balance(binance):
        """ 初始金额 """
        data = binance.cache_get(binance.parameter.db_coll_balance)
        if data:
            return data[binance.parameter.db_coll_balance_init]
        return None

    @staticmethod
    def get_min_dgs_number(binance):
        """ 已过滤(最小DGS数) """
        data = binance.cache_get(binance.parameter.db_coll_min_dgs)
        if data:
            for i in range(len(data)):
                data[i]["timestamp"] = time_stamp_date(data[i]["timestamp"])
            return data
        return []
